package TAIC.IPLM;
import java.util.*;
import java.io.*; 

public class AssignCluster {
	int totalCenters = 0 ;
	int DIM = 0 ;
	double 	center [][] = null ;
	
	static public void main ( String str []) {
		if ( str.length < 3 ) {
			System.out.println ( "please input:") ;
			System.out.println ( "all, configFile, codeBook" ) ;
			System.out.println ( " or one, dataFolder, codeBook") ;
			return ;
		}
		
		if ( str[0].equals( "all") ) ( new AssignCluster ( str[ 2 ])).generateAllDataSets( str[ 1 ] ) ;
		else if ( str[ 0 ].equals("one")) {
			String imageCorpus = str[ 1 ] + "\\ImageCorpus.txt" ; 
			String dstPath = str[ 1 ] + "\\IP\\svmCorpus" ;
			( new AssignCluster ( str[ 2 ])).generateOneDataSet( imageCorpus , dstPath ) ;
		}

//		if ( str.length < 3 ) {
//			System.out.println ( "please input the path the matFile, resultFile  and codeBook") ;
//			return ;
//		}
//		( new AssignCluster ( str[ 2 ])).selfTest( str[ 0 ] , str[ 1 ]) ;
	}
	
	public void selfTest ( String matFile, String resultFile ) {
		try {
			Scanner matScanner = new Scanner ( new File ( matFile ) );
			Scanner resultScanner = new Scanner ( new File (  resultFile )) ;
			int vecs = matScanner.nextInt () ; matScanner.nextLine() ;
			for (int i = 0 ; i < vecs ; i ++ ) {
				double vec [] = new double [ DIM ] ;
				for ( int j = 0 ; j < DIM; j++ ) vec[ j ] = matScanner.nextInt() ;
				normalize ( vec ) ; 
				int result = classify ( vec ) ;
				int correct = resultScanner.nextInt() ;  
				if ( result !=  correct ) {
					System.out.println ( "wrong at vector " + i + ": correct result is " + correct 
							+ " and your result is " + result ) ;
					return ;
				}
			}
			System.out.println ( "The program is correct in " + vecs + " vectors" )	; 
		}
		catch ( Exception e ) {
			e.printStackTrace () ;
		}
	}
	
	public AssignCluster ( String codeBook ) {
		try {
			Scanner bookScanner = new Scanner ( new File ( codeBook ) ) ;
			totalCenters = bookScanner.nextInt() ;
			DIM = bookScanner.nextInt() ; 
			center = new double [ totalCenters ][ DIM ] ;
			for ( int i = 0 ; i  < totalCenters ; i ++ ) 
				for ( int j = 0 ; j < DIM; j ++ ) 
					center [ i ][ j ] = bookScanner.nextDouble() ;
			bookScanner.close() ;
		}
		catch ( Exception e ) {
			e.printStackTrace() ;
		}		
	}
	
	public void generateAllDataSets ( String configFile ) {
		try{
			Scanner scanner = new Scanner ( new File ( configFile ));
			int datasets = scanner.nextInt () ;
			scanner.nextLine () ; 
			for ( int i = 0 ; i < datasets ; i ++ ) {
				String path = scanner.nextLine () ;
				String imageCorpus = path + "\\ImageCorpus.txt" ; 
				String dstPath = path + "\\IP\\svmCorpus" ;
				generateOneDataSet ( imageCorpus , dstPath) ;
			}
		}
		catch ( Exception e ) {
			e.printStackTrace() ;
		}
	}
		
	public void generateOneDataSet ( String imageCorpus , String dstPath ) {
		Vector < Node > corpus = new Vector < Node > () ;
		int maxClassNo = 0 ;
		try {
			Scanner scanner = new Scanner ( new File ( imageCorpus )); 
			while ( scanner.hasNextInt () ) {
				int classNo = scanner.nextInt() ;
				int wordNo = scanner.nextInt () ;
				String path = scanner.nextLine().trim() + ".sift" ; 
				if ( (new File(path)).exists() ) corpus.add( new Node ( classNo , wordNo, path ));
				if ( classNo > maxClassNo ) maxClassNo = classNo ; 
			}
			scanner.close() ;
			
			PrintStream fout = new PrintStream ( new File ( dstPath) ) ;
			fout.println ( corpus.size() + " " + ( maxClassNo + 1 ) /2 ) ;
			for ( Node node : corpus ) {
				if ( ! (new File ( node.path ).exists() ) )continue ; 
				int [] result = generateFile ( node.path ) ;
				fout.print ( node.classNo + " " + node.wordNo) ;
				for ( int i = 0 ; i < totalCenters ; i ++ ) 
					if ( result [ i ] !=0 ) fout.print ( " " + (i+1) + ":" + result [ i ] );
				fout.println ( ); 
			}
			fout.close() ;
		}
		catch ( Exception e ){
			e.printStackTrace() ;
		}
	}
	
	
	private int [] generateFile ( String imageFile ) {
		int result [] = new int [ totalCenters ] ;
		try {
			Scanner scanner = new Scanner ( new File ( imageFile));
			double vec [] = new double [ DIM ] ; 
			int imageVec = scanner.nextInt() ; scanner.next() ; 
			for ( int i = 0 ; i < imageVec ; i ++ ) {
				for ( int j = 0 ; j < DIM ; j ++ ) vec [ j ] = scanner.nextInt() ;
				normalize ( vec )  ; 
				result [ classify ( vec ) ] ++ ; 
			}
			scanner.close() ;
		}
		catch ( Exception e ) {
			e.printStackTrace() ;
		}
		return result ; 
		
	}
	
	void normalize ( double [ ] vec ) {
		double xx = 0 ; 
		for ( int i = 0 ; i < vec.length ; i ++ ) xx += vec [ i ] * vec [ i ] ;
		xx = Math.sqrt ( xx ) ; 
		for ( int i = 0 ; i < vec.length ; i  ++ ) vec[ i ] /= xx ; 
	}
	
	int classify ( double [] vec ) {
		double minDist = dist ( center[ 0 ], vec ) ;
		int result = 0 ; 
		for ( int i = 1 ; i < totalCenters ; i ++ ) {
			double temp = dist ( center [ i ] , vec ) ; 
			if ( temp < minDist ) {
				minDist = temp ;
				result = i ; 
			}
		}
		return result ; 
	}
	
	double dist ( double [] v1, double [] v2 ) {
		int min = Math.min(v1.length, v2.length);
		double result = 0 ;
		for ( int i = 0 ; i < min ; i ++ ) result += (v1[ i ] - v2[ i ]) * (v1[ i ] - v2[ i ]) ;
		return result ;
	}
	
	
	class Node {
		int classNo ;
		int wordNo ;
		String path ; 
		public Node ( int classNo , int wordNo, String path) {
			this.classNo = classNo ;
			this.wordNo = wordNo ;
			this.path = path ; 
		}
	}
}
